﻿Imports WiimoteLib
Imports System.Runtime.InteropServices
Imports WindowsHookLib

Public Class frmMain

    Public Connected As Boolean = False
    Dim WithEvents mHook As New MouseHook
    Dim WithEvents kHook As New KeyboardHook

    Private ButtonState As New Buttons
    Private InventorySlot As Integer = 1

    Private RMDown As Boolean = False
    Private LMDown As Boolean = False

    Public Structure Buttons
        Public UpBtn As KeyState
        Public DownBtn As KeyState
        Public LeftBtn As KeyState
        Public RightBtn As KeyState

        Public ZBtn As KeyState
        Public CBtn As KeyState
        Public PlusBtn As KeyState
        Public MinusBtn As KeyState
    End Structure

    Enum KeyState As Integer
        NotPressed
        PressedDown
        Releasing
    End Enum

#Region "Form Load Event"
    Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
        Try
            'Install the mouse hook
            mHook.InstallHook()
        Catch ex As Exception
            MessageBox.Show("Failed to install the mouse hook!." & Environment.NewLine & ex.Message, "Hook Error!", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try

        Try
            'Install the keyboard hook
            kHook.InstallHook()
        Catch ex As Exception
            MessageBox.Show("Failed to install the keyboard hook!." & Environment.NewLine & ex.Message, "Hook Error!", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try

        AddHandler wm.WiimoteChanged, AddressOf wm_WiimoteChanged
        AddHandler wm.WiimoteExtensionChanged, AddressOf wm_WiimoteExtensionChanged

        MouseEvents.Enabled = True
        MouseEvents.Start()
        MouseEvents2.Enabled = True
        MouseEvents2.Start()
    End Sub
#End Region

#Region "Hide the Window if we can't detect a Wii Remote."
    Public Delegate Sub InvokeDelegate()
    Private Sub HideMe()
        Me.Visible = False
        Me.Hide()
    End Sub
#End Region

    Private Sub wm_WiimoteChanged(ByVal sender As Object, ByVal args As WiimoteChangedEventArgs)
        lblbattery.Text = "Battery Status: " & Format(args.WiimoteState.Battery, "0.00") & "%"
        progbattery.Value = args.WiimoteState.Battery

        WiiButtons = args.WiimoteState.ButtonState
        Nunchuk = args.WiimoteState.NunchukState

        lbldirection.Text = "Up: " & WiiButtons.Up.ToString & Environment.NewLine & "Left: " & WiiButtons.Left.ToString _
        & Environment.NewLine & "Down: " & WiiButtons.Down.ToString & Environment.NewLine & "Right: " & WiiButtons.Right.ToString

        If args.WiimoteState.ButtonState.B = True Then
            lblBbtn.Text = "B Button: True"
            If IsMinecraftActiveWindow() Then
                LeftMouseDown()
            End If
        ElseIf args.WiimoteState.ButtonState.B = False Then
            lblBbtn.Text = "B Button: False"
            If IsMinecraftActiveWindow() Then
                LeftMouseUp()
            End If
        End If

        If args.WiimoteState.ButtonState.A = True Then
            lblAbtn.Text = "A Button: True"
            If IsMinecraftActiveWindow() Then
                RightMouseDown()
            End If
        ElseIf args.WiimoteState.ButtonState.A = False Then
            lblAbtn.Text = "A Button: False"
            If IsMinecraftActiveWindow() Then
                RightMouseUp()
            End If
        End If

    End Sub

#Region "Key Press Event - Close WiiCraft on ESC and Shift Key"
    Private Sub kHook_KeyDown(ByVal sender As Object, ByVal e As WindowsHookLib.KeyboardEventArgs) Handles kHook.KeyDown
        If e.KeyCode = Keys.Escape And e.Shift = True Then
            Application.Exit()
        End If
    End Sub
#End Region

#Region "Wii Remote - Extension Controller Change Event"
    Private Sub wm_WiimoteExtensionChanged(ByVal sender As Object, ByVal args As WiimoteExtensionChangedEventArgs)
        If args.Inserted Then
            wm.SetReportType(InputReport.IRExtensionAccel, True)
        Else
            wm.SetReportType(InputReport.IRAccel, True)
        End If
    End Sub
#End Region
#Region "Form Closing Event"
    Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As FormClosingEventArgs) Handles MyBase.FormClosing
        'A hack to make sure the program closes and releases all objects.
        Application.ExitThread()

        frmAbout.Close()
        frmConnect.Close()
        'Remove the mouse and keyboard hook.
        mHook.Dispose()
        kHook.Dispose()
        wm.SetLEDs(True, False, False, False)
        wm.Disconnect()
    End Sub
#End Region

#Region "Determine if Minecraft is the Active Window"

    Private Declare Function GetForegroundWindow Lib "user32.dll" () As IntPtr
    Private Declare Function GetWindowThreadProcessId Lib "user32.dll" (ByVal hwnd As IntPtr, ByRef lpdwProcessID As Integer) As Integer
    Private Declare Function GetWindowText Lib "user32.dll" Alias "GetWindowTextA" (ByVal hWnd As IntPtr, ByVal WinTitle As String, ByVal MaxLength As Integer) As Integer
    Private Declare Function GetWindowTextLength Lib "user32.dll" Alias "GetWindowTextLengthA" (ByVal hwnd As Long) As Integer

    Private Function IsMinecraftActiveWindow() As Boolean

        '—– Get the Handle to the Current Foreground Window —–
        Dim hWnd As IntPtr = GetForegroundWindow()
        If hWnd = IntPtr.Zero Then
            Return False
        End If

        '—– Find the PID of the Application that Owns the Window —–
        Dim pid As Integer = 0
        GetWindowThreadProcessId(hWnd, pid)

        If pid = 0 Then
            Return False
        End If

        '—– Get the actual PROCESS from the process ID —–
        Dim proc As Process = Process.GetProcessById(pid)
        If proc Is Nothing Then
            Return False
        End If

        '-- If the process has a WindowTitle of Minecraft, the game is running in a Window.
        '-- If the process has a process name of javaw.exe, then it's most likely Minecraft in full screen mode.
        If proc.MainWindowTitle = "Minecraft" Or proc.ProcessName = "javaw.exe" Then
            Return True
        Else
            Return False
        End If

    End Function
#End Region
#Region "Mouse Down Events"

    Private Declare Sub mouse_event Lib "user32.dll" (ByVal dwFlags As Int32, ByVal dx As Int32, ByVal dy As Int32, ByVal cButtons As Int32, ByVal dwExtraInfo As Int32)
    Private Declare Function SetCursorPos Lib "user32.dll" (ByVal X As Int32, ByVal Y As Int32) As Boolean

    <DllImport("user32.dll", SetLastError:=True)> Private Shared Function SendInput(ByVal cInputs As Integer, ByRef pInputs As INPUT, ByVal cbSize As Integer) As Integer
    End Function

    Const INPUT_MOUSE = 0
    Private Structure INPUT
        Public dwType As Integer            ' starts at 0   
        Public Mousedx As Integer           ' 4
        Public Mousedy As Integer           ' 8
        Public MousemouseData As Integer    ' 12
        Public MousedwFlags As Integer      ' 16
        Public Mousetime As Integer         ' 20
        Public MousedwExtraInfo As IntPtr   ' 24 - 28
    End Structure

    Const MOUSEEVENTF_LEFTDOWN As Integer = &H2
    Const MOUSEEVENTF_LEFTUP As Integer = &H4
    Const MOUSEEVENTF_MIDDLEDOWN As Integer = &H20
    Const MOUSEEVENTF_MIDDLEUP As Integer = &H40
    Const MOUSEEVENTF_MOVE As Integer = &H1
    Const MOUSEEVENTF_ABSOLUTE As Integer = &H8000
    Const MOUSEEVENTF_RIGHTDOWN As Integer = &H8
    Const MOUSEEVENTF_RIGHTUP As Integer = &H10

    Private Sub ClickMouse(ByVal MouseButton As Integer)
        Dim inputevents As New INPUT
        inputevents.Mousedx = 0
        inputevents.Mousedy = 0
        inputevents.MousemouseData = 0
        inputevents.MousedwFlags = MouseButton
        inputevents.Mousetime = 0
        inputevents.dwType = INPUT_MOUSE
        Dim cbSize As Integer = Marshal.SizeOf(GetType(INPUT))
        Dim result As Integer = SendInput(1, inputevents, cbSize)
        Dim lasterror As Integer = Marshal.GetLastWin32Error
    End Sub

    Private Sub LeftMouseDown()
        If LMDown = False Then
            ClickMouse(MOUSEEVENTF_LEFTDOWN) 'press left button
            LMDown = True
        End If
    End Sub

    Private Sub LeftMouseUp()
        ClickMouse(MOUSEEVENTF_LEFTUP) 'release left button
        LMDown = False
    End Sub

    Private Sub RightMouseDown()
        If RMDown = False Then
            ClickMouse(MOUSEEVENTF_RIGHTDOWN) 'press left button
            RMDown = True
        End If
    End Sub

    Private Sub RightMouseUp()
        ClickMouse(MOUSEEVENTF_RIGHTUP) 'release left button
        RMDown = False
    End Sub

    Private Mousepos As Mouselocation
    Private Structure Mouselocation
        Dim X As Long
        Dim Y As Long
    End Structure

    Private Sub mHook_MouseMove(ByVal sender As Object, ByVal e As WindowsHookLib.MouseEventArgs) Handles mHook.MouseMove
        Mousepos.X = e.X
        Mousepos.Y = e.Y
    End Sub

#End Region


    Private Sub MouseEvents_Tick(sender As System.Object, e As System.EventArgs) Handles MouseEvents.Tick
        lblMouse.Text = "Mouse Position: (" & Mousepos.X & "," & Mousepos.Y & ")"
        If IsMinecraftActiveWindow() = True Then
            Dim z As SendKeys.WINFOCUS = GetWinFocus(False, True)
            lblActiveWindow.Text = "Minecraft is the active window."

            'Code to handle the movement forward.
            If WiiButtons.Up = True Then
                If ButtonState.UpBtn = KeyState.NotPressed Then
                    ButtonState.UpBtn = KeyState.PressedDown
                    SendKeys.Send("W", z, True, False)
                End If
            ElseIf WiiButtons.Up = False Then
                If ButtonState.UpBtn = KeyState.PressedDown Then
                    ButtonState.UpBtn = KeyState.Releasing
                    SendKeys.Send("W", z, False, True)
                Else
                    ButtonState.UpBtn = KeyState.NotPressed
                End If
            End If

            'Code to handle the movement backward.
            If WiiButtons.Down = True Then
                If ButtonState.DownBtn = KeyState.NotPressed Then
                    ButtonState.DownBtn = KeyState.PressedDown
                    SendKeys.Send("S", z, True, False)
                End If
            ElseIf WiiButtons.Down = False Then
                If ButtonState.DownBtn = KeyState.PressedDown Then
                    ButtonState.DownBtn = KeyState.Releasing
                    SendKeys.Send("S", z, False, True)
                Else
                    ButtonState.DownBtn = KeyState.NotPressed
                End If
            End If

            'Code to handle the movement left.
            If WiiButtons.Left = True Then
                If ButtonState.LeftBtn = KeyState.NotPressed Then
                    ButtonState.LeftBtn = KeyState.PressedDown
                    SendKeys.Send("A", z, True, False)
                End If
            ElseIf WiiButtons.Left = False Then
                If ButtonState.LeftBtn = KeyState.PressedDown Then
                    ButtonState.LeftBtn = KeyState.Releasing
                    SendKeys.Send("A", z, False, True)
                Else
                    ButtonState.LeftBtn = KeyState.NotPressed
                End If
            End If

            'Code to handle the movement right.
            If WiiButtons.Right = True Then
                If ButtonState.RightBtn = KeyState.NotPressed Then
                    ButtonState.RightBtn = KeyState.PressedDown
                    SendKeys.Send("D", z, True, False)
                End If
            ElseIf WiiButtons.Right = False Then
                If ButtonState.RightBtn = KeyState.PressedDown Then
                    ButtonState.RightBtn = KeyState.Releasing
                    SendKeys.Send("D", z, False, True)
                Else
                    ButtonState.RightBtn = KeyState.NotPressed
                End If
            End If

            'Code to handle the Z Button.
            If Nunchuk.Z = True Then
                If ButtonState.ZBtn = KeyState.NotPressed Then
                    ButtonState.ZBtn = KeyState.PressedDown
                    SendKeys.Send("{SPACE}", z, True, False)
                End If
            ElseIf Nunchuk.Z = False Then
                If ButtonState.ZBtn = KeyState.PressedDown Then
                    ButtonState.ZBtn = KeyState.Releasing
                    SendKeys.Send("{SPACE}", z, False, True)
                Else
                    ButtonState.ZBtn = KeyState.NotPressed
                End If
            End If

            'Code to handle the C Button.
            If Nunchuk.C = True Then
                If ButtonState.CBtn = KeyState.NotPressed Then
                    ButtonState.CBtn = KeyState.PressedDown
                    SendKeys.Send("I", z, True, False)
                End If
            ElseIf Nunchuk.C = False Then
                If ButtonState.CBtn = KeyState.PressedDown Then
                    ButtonState.CBtn = KeyState.Releasing
                    SendKeys.Send("I", z, False, True)
                Else
                    ButtonState.CBtn = KeyState.NotPressed
                End If
            End If

            'Code to handle the Plus Button.
            If WiiButtons.Plus = True Then
                If ButtonState.PlusBtn = KeyState.NotPressed Then
                    ButtonState.PlusBtn = KeyState.PressedDown
                    If InventorySlot > 9 Then
                        InventorySlot = 1
                    Else
                        InventorySlot += 1
                    End If
                    SendKeys.Send("{" & CStr(InventorySlot) & "}", z, True, False)
                End If
            ElseIf WiiButtons.Plus = False Then
                If ButtonState.PlusBtn = KeyState.PressedDown Then
                    ButtonState.PlusBtn = KeyState.Releasing
                    SendKeys.Send("{" & CStr(InventorySlot) & "}", z, True, False)
                Else
                    ButtonState.PlusBtn = KeyState.NotPressed
                End If
            End If

            'Code to handle the Minus Button.
            If WiiButtons.Minus = True Then
                If ButtonState.MinusBtn = KeyState.NotPressed Then
                    ButtonState.MinusBtn = KeyState.PressedDown
                    If InventorySlot = 1 Then
                        InventorySlot = 9
                    Else
                        InventorySlot -= 1
                    End If
                    SendKeys.Send("{" & CStr(InventorySlot) & "}", z, True, False)
                End If
            ElseIf WiiButtons.Minus = False Then
                If ButtonState.MinusBtn = KeyState.PressedDown Then
                    ButtonState.MinusBtn = KeyState.Releasing
                    SendKeys.Send("{" & CStr(InventorySlot) & "}", z, True, False)
                Else
                    ButtonState.MinusBtn = KeyState.NotPressed
                End If
            End If

        Else
            lblActiveWindow.Text = "Minecraft is not the active window."
        End If
    End Sub


    Private LastX As Single = 0
    Private LastY As Single = 0

    Private Sub MouseEvents2_Tick(sender As System.Object, e As System.EventArgs) Handles MouseEvents2.Tick
        If IsMinecraftActiveWindow() = True Then
            Dim DiffX As Single = (Nunchuk.Joystick.X - LastX) + 5
            Dim DiffY As Single = (Nunchuk.Joystick.Y - LastY) + 5
            If Nunchuk.Joystick.X > 0.25 Then
                mouse_event(MOUSEEVENTF_MOVE, DiffX, 0, 0, 0)
            End If
            If Nunchuk.Joystick.X < -0.25 Then
                mouse_event(MOUSEEVENTF_MOVE, -DiffX, 0, 0, 0)
            End If
            If Nunchuk.Joystick.Y > 0.25 Then
                mouse_event(MOUSEEVENTF_MOVE, 0, -DiffY, 0, 0)
            End If
            If Nunchuk.Joystick.Y < -0.25 Then
                mouse_event(MOUSEEVENTF_MOVE, 0, DiffY, 0, 0)
            End If
            LastX = Nunchuk.Joystick.X
            LastY = Nunchuk.Joystick.Y
        End If
    End Sub

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        frmAbout.ShowDialog()
    End Sub
End Class
